﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Lidgren.Network;

namespace Netserver
{
    public class PlayerManager
    {
        public PlayerManager(NetworkManager netMan)
        {
            networkManager = netMan;
        }

        NetworkManager networkManager;
        List<Player> playersList = new List<Player>();
        List<int> freeIds = new List<int>();
        const int maxPlayerCount = 32;

        #region ID Management
        public int GetAvailableID()
        {
            if (playersList.Count >= maxPlayerCount) return -1;
            if (freeIds.Count < 1)
                return playersList.Count + 1;
            int val = freeIds.ElementAt<int>(0);
            freeIds.Remove(val);
            return val;
        }

        public void FreeID(int n)
        {
            if (n < 1 || n > maxPlayerCount) return;

            if (n != playersList.Count)
            {
                freeIds.Add(n);
            }
        }
        #endregion
        #region Player Handling
        public Player GetPlayer(NetConnection sender)
        {
            return playersList.Find(delegate(Player P) { return P.MyConnection == sender; });
        }

        public Player GetPlayer(int num)
        {
            return playersList.Find(delegate(Player P) { return P.MyNumber == num; });
        }

        public Player AddPlayer()
        {
            return AddPlayer(null, Vector2.Zero);
        }

        public Player AddPlayer(NetBuffer buff)
        {
            return AddPlayer(buff.ReadString(), new Vector2(buff.ReadSingle(), buff.ReadSingle()));
        }
        public Player AddPlayer(string name, Vector2 pos)
        {
            int freeID = GetAvailableID();
            if(freeID == -1) return null;

            Player P = new Player(name, freeID, pos);
            playersList.Add(P);
            return P;
        }

        public void RemPlayer(Player P)
        {
            playersList.Remove(P);
            FreeID(P.MyNumber);
            P = null;
        }

        public Player UpdatePlayer(NetBuffer buff)
        {
            string pName;
            UInt32 pNumber;
            Vector2 pPos;

            pNumber = buff.ReadUInt32(3);
            pPos.X = buff.ReadSingle();
            pPos.Y = buff.ReadSingle();
            pName = buff.ReadString();
            return UpdatePlayer((int)pNumber, pName, pPos);
        }

        public Player UpdatePlayer(int pNum, string pName, Vector2 pPos)
        {
            Player P;
            if ((P = playersList.Find(delegate(Player P2) { return P2.MyNumber == pNum; })) == null) return null;

            P.MyName = pName;
            P.MyPosition = pPos;
            Console.WriteLine("Updated player {0} ({1}) at {2},{3})", pName, pNum, pPos.X, pPos.Y);
            return P;
        }

        public void BuffAllPlayers(NetBuffer buff)
        {
            buff.Write("allplayers");
            buff.Write(playersList.Count, 3);

            foreach (Player P in playersList)
            {
                Player.BufferData(P, buff);
            }
        }
        #endregion
    }

    public class Player
    {
        #region Properties
        string myName;
        public string MyName
        {
            get { return myName; }
            set { myName = value; }
        }

        Vector2 myPosition;
        public Vector2 MyPosition
        {
            get { return myPosition; }
            set { myPosition = value; }
        }
        int myNumber;
        public int MyNumber
        {
            get { return myNumber; }
            internal set { myNumber = value; }
        }

        NetConnection myConnection;
        public NetConnection MyConnection
        {
            get { return myConnection; }
            set { myConnection = value; }
        }
        #endregion

        public Player(string name, int number, Vector2 pos)
        {
            MyName = name;
            MyNumber = number;
            MyPosition = pos;
        }

        #region Public Methods
        public static void ReadBuffer(NetBuffer buff)
        {
            string pName;
            UInt32  pNumber;
            Vector2 pPos;

            pNumber = buff.ReadUInt32(3);
            pPos.X = buff.ReadSingle();
            pPos.Y = buff.ReadSingle();
            pName = buff.ReadString();
            new Player(pName, (int)pNumber, pPos);
        }

        public static void BufferData(Player P, NetBuffer buff)
        {
            buff.Write((UInt32)P.MyNumber, 3);
            buff.Write(P.MyPosition.X);
            buff.Write(P.MyPosition.Y);
            buff.Write(P.MyName);
        }

        public static void BufferData(int pNum, Vector2 pPos, string pName, NetBuffer buff)
        {
            buff.Write((UInt32)pNum, 3);
            buff.Write(pPos.X);
            buff.Write(pPos.Y);
            buff.Write(pName);
        }
        #endregion
    }
}
